/* Foley C# Utilities
 * Copyright (C)2002 Rodney S. Foley
 *  
 * This program is free software; you can 
 * redistribute it and/or modify it under the 
 * terms of the GNU General Public License as 
 * published by the Free Software Foundation; 
 * either version 2 of the License, or (at your 
 * option) any later version.
 * 
 * This program is distributed in the hope that 
 * it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 * PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU 
 * General Public License along with this 
 * program; if not, write to: 
 * 
 *		Free Software Foundation, Inc., 
 *		59 Temple Place, Suite 330, 
 *		Boston, MA 02111-1307 USA
 * 
 *					- or -
 *  
 * http://opensource.org/licenses/gpl-license.php
 */

using System;
using System.Collections;

namespace Foley.Utilities.Collections
{
	/// <summary>
	/// Provides an abstract implementation of the <see cref="ICollection2"/> 
	/// interface.
	/// </summary>	
	/// <remarks>
	/// The main purpose of this is an all purpose base class that can be 
	/// extended by any class that wants to be a collection.
	/// </remarks>
	public abstract class Collection2Base : ICollection2
	{
		#region Protected Constructor
		/// <summary>
		/// Protected constructor for abstract class.
		/// </summary>
		protected Collection2Base() {}
		#endregion

		#region Public Member Properties
		/// <summary>
		/// When implemented by a class, gets the number of elements contained 
		/// in the collection.
		/// </summary>
		/// <value>
		/// The number of elements actually contained in the collection.
		/// </value>
		public abstract int Count { get; }

		/// <summary>
		/// Gets a <c>boolean</c> value idicating whether the collection is 
		/// empty or not.
		/// </summary>
		/// <value>
		/// <c>true</c> if the collection contains no elements; otherwise, 
		/// <c>false</c>.
		/// </value>
		public virtual bool IsEmpty { get { return Count <= 0; }}

		/// <summary>
		/// Gets a <c>boolean</c> value indicating whether the collection has a 
		/// fixed size.
		/// </summary>
		/// <value>
		/// <c>true</c> if the collection has a fixed size; otherwise, 
		/// <c>false</c>. The default is <c>false</c>.
		/// </value>
		public virtual bool IsFixedSize { get { return false; } }

		/// <summary>
		/// Gets a <c>boolean</c> value indicating whether the collection is 
		/// read-only.
		/// </summary>
		/// <value>
		/// <c>true</c> if the collection is read-only; otherwise, <c>false</c>. 
		/// The default is <c>false</c>.
		/// </value>
		public virtual bool IsReadOnly { get { return false; } }

		/// <summary>
		/// Gets a <c>boolean</c> value indicating whether access to the 
		/// collection is synchronized (thread-safe).
		/// </summary>
		/// <value>
		/// <c>true</c> if access to the collection is synchronized 
		/// (thread-safe); otherwise, <c>false</c>. The default is 
		/// <c>false</c>.
		/// </value>
		public virtual bool IsSynchronized { get { return false; } }

		/// <summary>
		/// Gets an <see cref="object"/> that can be used to synchronize access 
		/// to the collection.
		/// </summary>
		/// <value>
		/// An <see cref="object"/> that can be used to synchronize access to 
		/// the collection.
		/// </value>
		public virtual object SyncRoot { get { return this; } }
		#endregion

		#region Public Member Methods
		/// <summary>
		/// Removes all elements from the collection.
		/// </summary>
		public abstract void Clear();

		/// <summary>
		/// Copies the entire collection to a compatible one-dimensional 
		/// <see cref="Array"/>, starting at the specified <paramref name="index"/> 
		/// of the target <paramref name="array"/>.
		/// </summary>
		/// <param name="array">
		/// The one-dimensional <see cref="Array"/> that is the destination of 
		/// the elementscopied from the collection. The <see cref="Array"/> must 
		/// have zero-based indexing.
		/// </param>
		/// <param name="index">
		/// The zero-based <paramref name="index"/> in <paramref name="array"/> 
		/// at which copying begins.
		/// </param>
		/// <exception cref="ArgumentNullException">
		/// The <paramref name="array"/> is a <c>null</c> reference (<c>Nothing</c> 
		/// in Visual Basic).
		/// </exception>
		/// <exception cref="ArgumentOutOfRangeException">
		/// The <paramref name="index"/> is less than zero.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// <p>The <paramref name="array"/> is multidimensional.</p>
		/// -or-
		/// <p>The <paramref name="index"/> is equal to or greater than the 
		/// length of <paramref name="array"/>.</p>
		/// -or-
		/// <p>The number of elements in the collection is greater than
		/// the available space from <paramref name="index"/> to the end of 
		/// the destination <paramref name="array"/>.</p>
		/// </exception>
		public virtual void	CopyTo(Array array, int index)
		{
			if (array != null)
			{	
				if (0 <= index)
				{	
					if (array.Rank == 1)
					{	
						if (Count <= (array.Length - index))
						{
							if (index < array.Length)
							{	
								int i = index;

								foreach (object value in this)
								{
									array.SetValue(value, i);
									i++;
								}
							}
							else
								throw new ArgumentException("index is equal to or greater than the length of array.", "index");
						}
						else
							throw new ArgumentException("The number of elements is greater than the available space from index in the destination array.", "array");
					}
					else
						throw new ArgumentException("Multidimensional array", "array");
				}
				else
					throw new ArgumentOutOfRangeException("index" + index + "less than zero");
			}
			else
				throw new ArgumentNullException("array");
		}

		/// <summary>
		/// When implemented by a class, returns an <see cref="IEnumerator"/> 
		/// for the entire collection.
		/// </summary>
		/// <returns>
		/// An <see cref="IEnumerator"/> for the entire collection.
		/// </returns>
		public abstract IEnumerator GetEnumerator();
		#endregion

		#region Protected Member Methods
		/// <summary>
		/// Determins if the specified value is contained in the specified 
		/// <paramref name="collection"/>.
		/// </summary>
		/// <param name="collection">
		/// The <see cref="ICollection"/> used to test the specified 
		/// <see cref="object"/> against.
		/// </param>
		/// <param name="value">
		/// The <see cref="object"/> used to see if it is contained in the 
		/// specified <see cref="ICollection"/>.
		/// </param>
		/// <returns>
		/// <c>true</c> if value is contained in collection; otherwise 
		/// <c>false</c>
		/// </returns>
		protected bool IsContainedIn(ICollection collection, object value)
		{
			bool isContained = false;

			foreach (object obj in collection)
			{
				if (obj.Equals(value))
				{
					isContained = true;
					break;
				}
			}

			return isContained;
		}
		#endregion
	}
}
